#include "NiceTrySolver.hpp"
#include <cstdlib>
#include <algorithm>

void	NiceTrySolver::execute() EXC_THROWER()
{
	EXC_RETHROW_BEGIN()
	{
		unsigned    iteration = 0;
        unsigned    amelior_iteration = 0;
        unsigned	pred_sol1;
		unsigned	pred_sol2;
		unsigned	cur;
		unsigned	nb_ameliorations = 0;
		unsigned	nb_ameliorations_by_tree = 0;
		std::map<unsigned, unsigned>	tindex_by_client;
		TourneeEvalResult	evalres;
		TourneeEvalResult	eval_insert;
		TourneeEvalResult	eval_insert_n;
		TourneeEvalResult	eval_erase;
		TourneeEvalResult	eval_erase_n;
		SolutionEval		evalsol;
		SolutionEval		evalsolbest;
		
		bool				tree_usage = true;
		unsigned			tmp;
		
		//ntBasicSolver.execute();
		
		std::cout << ntBasicSolver.getBestSolution().toString() << std::endl;
		
		ntSolution = ntBasicSolver.getBestSolution();
		ntBasicSolver.getBestSolution().eval(&evalsolbest);
		
		std::cout << evalsolbest.toString() << std::endl;
		
		if (ntMerger.getTable().size() != soVRPTW.size())
		{
			ntMerger.getTable().clear();
			ntBasicSolver.getBestSolution().fillDeque(ntMerger.getTable());
		}
		
		random_shuffle(ntMerger.getTable().begin(), ntMerger.getTable().end());
		
		for (unsigned i = 0 ; i < ntMerger.getTable().size() ; i++)
			tindex_by_client[ntMerger.getTable()[i]] = i;
		
		for (iteration = 0 ;; iteration++)
		{
			if ((iteration) > ntMaxIt)
				break;
			
			/*
			for (unsigned i = 0 ; i < 2000 ; i++)
			{
				pred_sol1 = rand() % ntMerger.getTable().size();
				pred_sol2 = rand() % ntMerger.getTable().size();
				
				cur = ntMerger.getTable()[pred_sol2];
				ntMerger.getTable()[pred_sol2] = ntMerger.getTable()[pred_sol1];
				ntMerger.getTable()[pred_sol1] = cur;
			}
			*/
			
			//random_shuffle(ntMerger.getTable().begin(), ntMerger.getTable().end());
			ntMerger.execute();
			//std::cout << ntMerger.getBestSolution().toString() << std::endl;
			
			//getchar();
			
			for (unsigned i = 0 ; i < ntMerger.getTable().size() ; i++)
			{
				cur = ntMerger.getTable()[i];
				
				//std::cout << "cur : " << cur << std::endl;
				
				pred_sol2 = ntMerger.getBestSolution().getPredecessorOf(cur);
				
				//std::cout << "cur : " << cur << std::endl;
				pred_sol1 = ntBasicSolver.getBestSolution().getPredecessorOf(cur);
				
				
				if (pred_sol1 == pred_sol2)
					continue;
				else
				{
					if (pred_sol2 != DEPOT)
					{
						// attention : cas où les tournees sont les memes ! probleme dacces
						unsigned	i_insert;
						unsigned	i_erase;
						
						i_insert = ntBasicSolver.getBestSolution().getTourneeByClient(cur);
						i_erase = ntBasicSolver.getBestSolution().getTourneeByClient(pred_sol2);
						
						if (i_insert == i_erase)
						{
							Tournee&	t_edit = ntBasicSolver.getBestSolution()[i_insert];
							
							t_edit.eval(&eval_insert);
							
							t_edit.erase(pred_sol2);
							t_edit.insertClient(Tournee::INSERT_BEFORE, pred_sol2, cur);
							t_edit.eval(&evalres);
							
							// ici, modifier uniquement si la longueur de la tournee
							// est inferieure
							
							
							if (evalres.erValable  && (evalres.erTotalDistance < eval_insert.erTotalDistance))
							{
								//std::cout << "valable !" << std::endl;
								// il faut switcher les
								// switcher dans table
								ntBasicSolver.getBestSolution().validateTournee(i_insert);
								
							}
							else
							{
								ntBasicSolver.getBestSolution().restoreTournee(i_insert);
							}
						}
						else
						{
							unsigned	t_erase_size = 0;
							double		total_distance = 0.;
							double		total_distance_n = 0.;
							
							Tournee&	t_insert = ntBasicSolver.getBestSolution()[i_insert];
							Tournee&	t_erase = ntBasicSolver.getBestSolution()[i_erase];
							
							t_erase_size = t_erase.getNbClients();
							
							t_insert.eval(&eval_insert);
							t_erase.eval(&eval_erase);
							total_distance = eval_insert.erTotalDistance + eval_erase.erTotalDistance;
							
							
							t_insert.insertClient(Tournee::INSERT_BEFORE, pred_sol2, cur);
							t_insert.eval(&eval_insert_n);
							
							if (eval_insert_n.erValable)
							{
								t_erase.erase(pred_sol2);
								ntBasicSolver.getBestSolution().validateTournee(t_erase.toId);
								ntBasicSolver.getBestSolution().validateTournee(t_insert.toId);
								
								
								
								/*
								if (t_erase_size == 1)
								{
									// std::cout << "valable !" << std::endl;
									t_erase.erase(pred_sol2);
									ntBasicSolver.getBestSolution().validateTournee(t_erase.toId);
									ntBasicSolver.getBestSolution().validateTournee(t_insert.toId);
								}
								else
								{
									
									t_erase.erase(pred_sol2);
									t_erase.eval(&eval_erase_n);
									
									total_distance_n = eval_insert_n.erTotalDistance + eval_erase_n.erTotalDistance;
									
									if (total_distance_n <= total_distance)
									{
										ntBasicSolver.getBestSolution().validateTournee(t_erase.toId);
										ntBasicSolver.getBestSolution().validateTournee(t_insert.toId);	
									}
									else
									{
										ntBasicSolver.getBestSolution().restoreTournee(t_insert.toId);
										ntBasicSolver.getBestSolution().restoreTournee(t_erase.toId);
									}
								}
								*/
								
							}
							else
							{
								// mettre la plus faible sur le noeud courant
								// car proba de merge sur autre plus elevee
								ntBasicSolver.getBestSolution().restoreTournee(t_insert.toId);
								ntBasicSolver.getBestSolution().restoreTournee(t_erase.toId);
							}
						}

					}
				}
			}
			
			
			
			ntBasicSolver.getBestSolution().eval(&evalsol);
			
			if (evalsol < evalsolbest)
			{
				nb_ameliorations++;
				
				if (tree_usage)
					nb_ameliorations_by_tree++;
				
				
				evalsolbest = evalsol;
				ntSolution = ntBasicSolver.getBestSolution();
				//ntSolution.eval(&evalsolbest);
				//ntBasicSolver.getBestSolution() = ntSolution;
				//std::cout << ntSolution.toString() << std::endl;
				//std::cout << ntBasicSolver.getBestSolution().toString() << std::endl;
				//std::cout << evalsolbest.toString() << std::endl;
				//std::cout << "AMELIORATION " << nb_ameliorations << "@" << iteration << " (" << nb_ameliorations_by_tree << " by tree)" << std::endl;
				ntMerger.getTable().clear();
				ntBasicSolver.getBestSolution().fillDeque(ntMerger.getTable());
				
				for (unsigned i = 0 ; i < ntMerger.getTable().size() ; i++)
					tindex_by_client[ntMerger.getTable()[i]] = i;
				
				tree_usage = true;
                
                amelior_iteration = iteration;
			}
			else
			{
				tree_usage = false;
				//random_shuffle(ntMerger.getTable().begin(), ntMerger.getTable().end());
				
				for (unsigned i = 0 ; i < ntMerger.getTable().size() ; i++)
					tindex_by_client[ntMerger.getTable()[i]] = i;
				
                if ((iteration - amelior_iteration) > 200)
                {
                   random_shuffle(ntMerger.getTable().begin(), ntMerger.getTable().end()); 
                }
                else
                {
                    for (unsigned i = 0 ; i < ((iteration - amelior_iteration)) ; i++)
                    {
                        pred_sol1 = rand() % ntMerger.getTable().size();
                        pred_sol2 = rand() % ntMerger.getTable().size();
                    
                        cur = ntMerger.getTable()[pred_sol2];
                        ntMerger.getTable()[pred_sol2] = ntMerger.getTable()[pred_sol1];
                        ntMerger.getTable()[pred_sol1] = cur;
                    }
                }
			}
			
			//std::cout << evalsol.toString() << std::endl;
			
		}
		
		
		
		soBestSolution = &ntSolution;
	}
	EXC_RETHROW_END()
}
